package hjd.game.gameserver;

/**
 * @author hujiangdi
 * @date 28/8/2023
 */

import com.alibaba.fastjson.JSONObject;
import hjd.game.common.OperationType;
import hjd.game.common.PlayerColorEnum;
import hjd.game.model.Player;
import hjd.game.model.PlayerDTO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.SynchronousQueue;

@Component
@ServerEndpoint("/websocket")
@Slf4j
public class Server {
    /**
     * 玩家池
     */
    private static final ConcurrentHashMap<String, Server> playerPool = new ConcurrentHashMap<>();
    /**
     * 玩家信息
     */
    private static final ConcurrentHashMap<String, Player> playerInfo = new ConcurrentHashMap<>();

    private static final SynchronousQueue<Session> synchronousQueue = new SynchronousQueue<>();

    /**
     * 已经被创建了的
     */
    private static ConcurrentHashMap<String, Server> createdPlayer = new ConcurrentHashMap<>();

    private Session session;

    private Player player;

    /**
     * 连接成功后调用的方法
     */
    @OnOpen
    public void webSocketOpen(Session session) throws IOException {
        Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
        String userId = requestParameterMap.get("userId").get(0);
        String userName = requestParameterMap.get("userName").get(0);
        this.session = session;
        if (!playerPool.containsKey(userId)) {
            int locationX = getLocation(151);
            int locationY = getLocation(151);
            String color = PlayerColorEnum.getValueByCode(getLocation(1) + 1);
            Player newPlayer = new Player(userId, userName, locationX, locationY,color,null);
            playerPool.put(userId, this);
            this.player = newPlayer;
            //存放玩家信息
            playerInfo.put(userId,newPlayer);
        }
        log.info("玩家:{}|{}连接了服务器", userId, userName);
        // 创建游戏对象
        this.createPlayer(userId);
    }

    /**
     * 接收到消息调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException, InterruptedException {
        log.info("用户:{},消息{}:",this.player.getPlayerId(),message);
        PlayerDTO playerDTO = new PlayerDTO();
        Player player = JSONObject.parseObject(message, Player.class);
        List<Player> players = new ArrayList<>();
        players.add(player);
        playerDTO.setPlayers(players);
        playerDTO.setType(OperationType.MOVE_OBJECT.getCode());
        String returnMessage = JSONObject.toJSONString(playerDTO);
        //广播所有玩家
        for (String key : playerPool.keySet()) {
            synchronized (session){
                String playerId = playerPool.get(key).player.getPlayerId();
                if(!playerId.equals(this.player.getPlayerId())){
                    playerPool.get(key).session.getBasicRemote().sendText(returnMessage);
                }
            }
        }
    }

    /**
     * 关闭连接调用方法
     */
    @OnClose
    public void onClose() throws IOException {
        String playerId = this.player.getPlayerId();
        log.info("玩家{}退出!", playerId);
        Player playerBaseInfo = playerInfo.get(playerId);
        //移除玩家
        for (String key : playerPool.keySet()) {
            playerPool.remove(playerId);
            playerInfo.remove(playerId);
            createdPlayer.remove(playerId);
        }
        //通知客户端销毁对象
        destroyPlayer(playerBaseInfo);
    }

    /**
     * 出现错误时调用的方法
     */
    @OnError
    public void onError(Throwable error) {
        System.out.println("用户错误:" + this.player.getPlayerId() + ",原因:" + error.getMessage());
        error.printStackTrace();
    }

    private void createPlayer(String playerId) throws IOException {
        if (!createdPlayer.containsKey(playerId)) {
            List<Player> players = new ArrayList<>();
            for (String key : playerInfo.keySet()) {
                Player playerBaseInfo = playerInfo.get(key);
                players.add(playerBaseInfo);
            }
            PlayerDTO playerDTO = new PlayerDTO();
            playerDTO.setType(OperationType.CREATE_OBJECT.getCode());
            playerDTO.setPlayers(players);
            String syncInfo = JSONObject.toJSONString(playerDTO);
            for (String key :
                    playerPool.keySet()) {
                playerPool.get(key).session.getBasicRemote().sendText(syncInfo);
            }
            // 存放
            createdPlayer.put(playerId, this);
        }
    }

    private void destroyPlayer(Player playerBaseInfo) throws IOException {
        PlayerDTO playerDTO = new PlayerDTO();
        playerDTO.setType(OperationType.DESTROY_OBJECT.getCode());
        List<Player> players = new ArrayList<>();
        players.add(playerBaseInfo);
        playerDTO.setPlayers(players);
        String syncInfo = JSONObject.toJSONString(playerDTO);
        for (String key :
                playerPool.keySet()) {
            playerPool.get(key).session.getBasicRemote().sendText(syncInfo);
        }
    }

    /**
     * 发送消息
     *
     * @throws Exception
     */
    private void sendMessage() throws Exception {
        this.session.getBasicRemote().sendText("");
    }

    private int getLocation(Integer seed){
        Random random = new Random();
        return random.nextInt(seed);
    }
}
